人生像是一列火車,旅程中總是會搭載著不同貨物,走得越遠掛載的越多,包括肥肉。
在法國搭高速火車時,曾經收到朋友的告誡:千萬不要自己亂換車廂,尤其是火車停在某一站的時候。
原本不以為意,但聽到以下的故事就頓時聽話了:
某人在火車停靠在某一站時,因為肚子痛急著想上廁所,但自己座位的那節車廂廁所卻有人,於是到隔壁的車廂去上,拉肚子總是不好解決,花了許多時間,等到舒緩之後,突然意會到怎麼火車還沒開,於是走回去原車廂時,驚!發現原本坐的那節車廂不見了!完全被shift()
掉了!
這是真實的故事,因為法國很大,火車從巴黎出發,一路往南開會經過好幾個城市,為了節省資源,會特意在訂票時就把到達同城市的旅客集中在固定的幾節車廂,這樣一來只要到達某站,就會把指定的那幾節車廂拆卸下來(切斷),然後其餘的車廂繼續開往其他城市。反過來想,這列火車也是可以陸續和其他的車廂合併,一起開往巴黎。
火車的車廂就像是陣列,一節節的車廂合併串起來就是concat()
了。 轉大人成功了
concat() 可以在陣列中與其他多個陣列合併,並回傳新的陣列。原陣列不會被改變。我們可以將要合併的陣列或元素,多個或單個,以引數的方式,讓原陣列與這些要併入的陣列或元素合併在一起。
Array.prototype.concat() - JavaScript | MDN
concat() 方法
原型: Array.prototype.concat()
功能: 用來合併兩個或多個陣列或元素。concat()不會改變原有的陣列,回傳一個包含呼叫陣列本身的值,作為代替的是回傳一個新陣列。
改變: 不會改變原有的陣列
語法: var new_array = old_array.concat(value1[, value2[, ...[, valueN]]])
回傳值: 一個新的陣列實體。
參數: valueN 陣列以及/或者值,用來合併成一個新的陣列。
我們以參數傳入的方式,把要合併的陣列或元素放在( )裡,這部分concat()
非常彈性,要多個、單個、或陣列與物件的方式都可以,幾乎是給什麼吃什麼。 好雜食啊
const arr1 = ["Hi", "Wow"];
// 如果將陣列以參數傳入concat(),它會拆開這些陣列,並將元素加入原本的陣列。
const arr2 = arr1.concat([1, 2, 3]);
const arr3 = arr2.concat(4, 5, 6);
const arr4 = arr3.concat({ a: 42 });
arr1; // [ 'Hi', 'Wow' ]
arr2; // [ 'Hi', 'Wow', 1, 2, 3 ]
arr3; // [ 'Hi', 'Wow', 1, 2, 3, 4, 5, 6 ]
arr4; // [ 'Hi', 'Wow', 1, 2, 3, 4, 5, 6, { a: 42 } ]
既然是多個,我們也可以一次就把要合併的元素或物件合併上去。像這樣:
const arr1 = ["Hi", "Wow"];
const arr2 = arr1.concat([1, 2, 3], 4, 5, 6, { a: 42 });
arr1; // [ 'Hi', 'Wow' ]
arr2; // [ 'Hi', 'Wow', 1, 2, 3, 4, 5, 6, { a: 42 } ]
// 字串也可以
const colorName = "purple"
const allColor4 = [...warmColor, ...coldColor, colorName];
allColor4; // [ 'red', 'yellow', 'blue', 'gray', 'purple' ]
雖然我們可以將陣列以參數傳入concat()
,它會自動拆開這些陣列,但並不表示多層的陣列就可行,要注意的是,concat()
只會拆開提供給它的第一層陣列,而不會拆開第二層陣列(陣列中的陣列)。也就是說concat()
不會以遞迴(recursively)的方式,把多層的陣列攤平。 想得美
const arr = [1, 2, 3];
arr.concat([4, 5], 6); // [1,2,3,4,5,6];
arr.concat([7, [8, 9]]); // [ 1, 2, 3, 7, [ 8, 9 ] ]
看到網路上討論到,使用concat()
時,如果沒有給參數,就相當是原陣列與一個空陣列拼接,返回的原陣列,就算是原陣列的深拷貝。
但是利用concat()
來複製陣列,只限用在結構較簡單的陣列上,如果運用在比較複雜與多層的物件上,這個方法就行不通了。
let arr = ["hi","wow",["O","X"]]
let arr2 = arr.concat();
// 試著修改第一層和第二層的陣列元素
arr[2][0]="OOO"
arr[0] = "Hello"
arr; // ["Hello", "wow", ["OOO", "X"]]
arr2; //["hi", "wow", ["OOO", "X"]]
我們可以觀察到,如果修改第一層的arr[0]
這個元素為"Hello"
,arr2[0]
並沒有被修改到,但是當我們修改arr[2][0]
為"OOO"
的時候,arr2[2][0]
也會跟著改成"OOO"
。如果要拿concat()
來複製物件型態的資料時,還是要特別注意這點。
還記得我們前幾篇有介紹,從陣列尾端來「新增」元素的push()
方法嗎?看起來push()
做的事和concat()
很像,都是從陣列的尾端加東西,不同之處在哪裡?
concat() | 從原陣列複製一個新的陣列,在新陣列上進行操作,不會改變原陣列的值。 | 會拆開參數,把元素加進去 |
---|---|---|
push() | 在原陣列上修改,執行push()原陣列的值也會變 | 參數是陣列時,把整個陣列參數作為一個元素 |
還有另外一種方式可以達到和concat()
一樣效果的我們把其餘參數(rest parameter),這個方式也很方便,效果也一樣。
const warmColor = ["red", "yellow"]
const coldColor = ["blue", "gray"]
// 使用 concat()
const allColor1 = [].concat(warmColor, coldColor);
// [ 'red', 'yellow', 'blue', 'gray' ]
// 也可以寫成
const allColor2 = warmColor.concat(coldColor);
// [ 'red', 'yellow', 'blue', 'gray' ]
const allColor3 = [...warmColor, ...coldColor];
// [ 'red', 'yellow', 'blue', 'gray' ]
但據說還是有些許不一樣,我們有機會再好好的測試。 機會?鐵人賽後吧
這三種吃小菜的方法:push()
、concat()
和其餘參數(rest parameter)大家喜歡哪一種?
希望這幾天的小菜,可以讓大家至少對如何刪除或增加陣列的方法有一個概觀,路還很長、小菜還很多樣,還請大家慢慢品嚐囉。
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~
嗨大師你好~
warmColor應該沒定義吧?
歐歐,偶不是大師啦~
你說的定義,是指 const warmColor = ["red", "yellow"]
這個嗎?
恩是的,但感覺應該是你寫的時候的一種個人習慣拉XD
原來法國的火車會這樣 XD 好有趣
是滴,應該說歐洲很多的火車都這樣,因為地大,所以經過的城鎮很多,所以如果不斷頭斷尾,拉著這麼多車廂應該蠻耗效能的~